package lion.spider.executor;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang.StringUtils;

import lion.crawl.fetch.Content;
import lion.crawl.fetch.HttpDownloader;
import lion.crawl.rule.JsoupRule;
import lion.crawl.rule.ParseRule;
import lion.crawl.rule.RegexFieldRule;
import lion.dev.io.FileUtil;
import lion.dev.lang.Lang;
import lion.dev.lang.MapJ;
import lion.dev.web.Validator;
import lion.dev.web.paging.PagedVo;
import lion.framework.core.db.SessionFactory;
import lion.framework.core.web.anno.Namespace;
import lion.framework.core.web.anno.Param;
import lion.framework.core.web.anno.Path;
import lion.framework.core.web.anno.Result;
import lion.framework.core.web.anno.View;
import lion.framework.core.web.request.Request;
import lion.framework.core.web.views.ResultType;
import lion.spider.model.CrawlerConfig;
import lion.spider.model.ExtractRule;
import lion.spider.model.PageRule;

/**
 * 
 * @author lion
 * @email hl_0074@sina.com
 * @date 2016年5月9日
 */
@Namespace(value = "/#{admin}/ds")
public class SpiderExecutor {

	@Path("spider")
	@Result(@View("/WEB-INF/template/spider/index.jsp"))
	public String index() {

		return "success";
	}

	/**
	 * 测试页面解析
	 */
	@Path("spider/parse")
	@Result(@View(type = ResultType.JSON))
	public String testParse(@Param("url") String url, Request request) {

		HttpDownloader downloader = new HttpDownloader();
		Content content = null;
		try {
			content = downloader.fatch(url);
		} catch (IOException e) {
			request.addError("msg", e.getMessage());
			return "success";
		}
		String html = FileUtil.read(content.getContent());

		MapJ result = new MapJ();

		List<ExtractRule> extractRules = ExtractRule.list(0, -1, "where configId=:configId", request, SessionFactory.getCurrentDB());
		List<ParseRule> rules = new ArrayList<>();
		MapJ jsoupMap = new MapJ();
		for (ExtractRule er : extractRules) {
			if (er.getType() == 1) {
				rules.add(new RegexFieldRule(er.getName(), er.getRule()));
			} else if (er.getType() == 2) {
				jsoupMap.put(er.getName(), er.getRule());
			}
		}
		if (!jsoupMap.isEmpty()) {
			rules.add(new JsoupRule(jsoupMap));
		}
		for (ParseRule r : rules) {
			r.extract(html, result);
		}
		request.addModel("json", result);
		return "success";
	}

	/**
	 * 编辑抓取配置
	 */
	@Path("spider/config/edit")
	@Result(@View("/WEB-INF/template/spider/editconfig.jsp"))
	public String editConfig(Request request) {

		int id = request.getInt("id");
		if (id > 0) {
			request.addModel("config", CrawlerConfig.load(id));
		}
		return "success";
	}

	/**
	 * 保存抓取配置
	 */
	@Path("spider/config/save")
	@Result(@View(type = ResultType.JSON))
	public String saveConfig(Request request) {

		CrawlerConfig cc = CrawlerConfig.create(request);

		if (CrawlerConfig.load("where name=:name", request, SessionFactory.getCurrentDB()) != null) {
			request.addError("msg", "相同配置名称已存在");
			return "success";
		}
		cc.save();

		return "success";
	}

	/**
	 * 更新抓取配置
	 */
	@Path("spider/config/update")
	@Result(@View(type = ResultType.JSON))
	public String updateConfig(Request request) {

		CrawlerConfig cc = CrawlerConfig.create(request);

		if (CrawlerConfig.load("where name=:name and id<>:id", request, SessionFactory.getCurrentDB()) != null) {
			request.addError("msg", "相同配置名称已存在");
			return "success";
		}
		cc.update();

		return "success";
	}

	/**
	 * 删除抓取配置
	 */
	@Path("spider/config/delete")
	@Result(@View(type = ResultType.JSON))
	public String deleteConfig(Request request) {

		int[] ids = Validator.toIntArray(request.getString("ids"));
		if (ids.length > 0) {
			// 删除配置
			CrawlerConfig.delete(ids);
			// 删除规则
			SessionFactory.getCurrentDB().update("delete from ExtractRule where configId in(" + Lang.join(ids) + ")");
			SessionFactory.getCurrentDB().update("delete from PageRule where configId in(" + Lang.join(ids) + ")");
		}
		return "success";
	}

	/**
	 * 列出抓取配置
	 */
	@Path("spider/config/list")
	@Result(@View(type = ResultType.JSON))
	public String listConfig(Request request) {

		List<CrawlerConfig> configs = CrawlerConfig.list(-1);
		request.addModel("data", configs);

		return "success";
	}

	/**
	 * 列出抓取路径规则
	 */
	@Path("spider/pagerule/list")
	@Result(@View(type = ResultType.JSON))
	public String listPageRule(Request request) {

		int page = request.getInt("page", 1);
		int size = request.getInt("size", 20);

		int configId = request.getInt("configId");
		if (configId <= 0) { return "success"; }

		int count = PageRule.count("where configId=:configId", request);

		PagedVo<PageRule> pagedVo = new PagedVo<>(count);

		pagedVo.getPaging().setPageNumber(page);
		pagedVo.getPaging().setPageSize(size);

		pagedVo.setVos(
				PageRule.list(pagedVo.getPaging().getStartRowNumber(), pagedVo.getPaging().getPageSize(), " where configId=:configId", request, SessionFactory.getCurrentDB()));

		request.addModel("json", pagedVo);

		return "success";
	}

	/**
	 * 编辑抓取路径规则
	 */
	@Path("spider/pagerule/edit")
	@Result(@View("/WEB-INF/template/spider/editpagerule.jsp"))
	public String editPageRule(Request request) {

		int id = request.getInt("id");
		if (id > 0) {
			request.addModel("rule", PageRule.load(id));
		}
		if (request.containsKey("configId")) {
			request.addModel("configId", request.getString("configId"));
		}

		return "success";
	}

	/**
	 * 保存抓取路径规则
	 */
	@Path("spider/pagerule/save")
	public void savePageRule(PageRule pr) {

		pr.save();
	}

	/**
	 * 更新抓取路径规则
	 */
	@Path("spider/pagerule/update")
	public void updatePageRule(PageRule pr) {

		if (StringUtils.isNotBlank(pr.getPattern())) {
			pr.update();
		}
	}

	/**
	 * 删除抓取路径规则
	 */
	@Path("spider/pagerule/delete")
	public void deletePageRule(Request request) {

		int[] ids = Validator.toIntArray(request.getString("ids"));
		if (ids.length > 0) {
			PageRule.delete(ids);
		}
	}

	/**
	 * 编辑页面解析规则
	 */
	@Path("spider/extractrule/edit")
	@Result(@View("/WEB-INF/template/spider/editextractrule.jsp"))
	public String editExtractRule(Request request) {

		int id = request.getInt("id");
		if (id > 0) {
			request.addModel("rule", ExtractRule.load(id));
		}
		if (request.containsKey("configId")) {
			request.addModel("configId", request.getString("configId"));
		}
		return "success";
	}

	/**
	 * 保存页面解析规则
	 */
	@Path("spider/extractrule/save")
	public void saveExtractRule(ExtractRule rule) {

		rule.save();
	}

	/**
	 * 列出页面解析规则
	 */
	@Path("spider/extractrule/list")
	@Result(@View(type = ResultType.JSON))
	public String listExtractRule(Request request) {

		int page = request.getInt("page", 1);
		int size = request.getInt("size", 20);

		int configId = request.getInt("configId");
		if (configId <= 0) { return "success"; }

		int count = ExtractRule.count("where configId=:configId", request);

		PagedVo<ExtractRule> pagedVo = new PagedVo<>(count);

		pagedVo.getPaging().setPageNumber(page);
		pagedVo.getPaging().setPageSize(size);

		pagedVo.setVos(
				ExtractRule.list(pagedVo.getPaging().getStartRowNumber(), pagedVo.getPaging().getPageSize(), " where configId=:configId", request, SessionFactory.getCurrentDB()));

		request.addModel("json", pagedVo);

		return "success";

	}

	/**
	 * 更新页面解析规则
	 */
	@Path("spider/extractrule/update")
	public void updateExtractRule(ExtractRule rule) {

		rule.update();
	}

	/**
	 * 删除页面解析规则
	 */
	@Path("spider/extractrule/delete")
	public void deleteExtractRule(Request request) {

		int[] ids = Validator.toIntArray(request.getString("ids"));
		if (ids.length > 0) {
			ExtractRule.delete(ids);
		}
	}
}
